import { defineStore, acceptHMRUpdate } from "pinia";
import { computed, onMounted, reactive } from "vue";
import { FopApi } from "@/lib/api";
import { getBaseName } from "@/lib/utils";
import { Playlist, type PlaylistObject } from "@/lib/playlist";
import usePlaylistStore from "./playlist";

const useStarStore = defineStore("star", () => {
    const playlist = usePlaylistStore();

    // 所有的收藏列表
    const all = reactive<string[]>([]);
    const set = reactive(new Set<string>());

    // 启动时加载收藏列表
    onMounted(async () => {
        const res = await FopApi.globInData("star/*.json");
        all.length = 0;
        set.clear();
        all.push(...res.map(getBaseName));
        all.forEach(set.add.bind(set));
    });

    /**
     * 创建收藏列表
     * @param name 收藏列表名称
     * @returns 是否创建成功
     */
    async function build(name: string): Promise<boolean> {
        // 创建收藏列表
        try {
            await FopApi.writeJson(`star/${name}`, []);
            set.add(name);
            all.push(name);
        } catch (error) {
            console.error("创建收藏列表", name, "失败", error);
            return false;
        }

        return true;
    }

    /**
     * 读取某个收藏列表到播放列表
     * @param name 收藏列表名称
     * @returns 播放列表，读取失败则返回 undefined
     */
    async function load(name: string): Promise<PlaylistObject | undefined> {
        try {
            // 加载收藏列表
            const data = await FopApi.readJson<PlaylistObject["items"]>(`star/${name}`);

            // 返回播放列表
            const playlistObject = {
                ...Playlist.object(),
                items: data,
            };

            // 进行数据校验
            return Playlist.check(playlistObject);
        } catch (error) {
            console.error("读取收藏列表", name, "失败", error);
            return;
        }
    }

    /**
     * 保存播放列表到某个收藏列表
     * @param name 收藏列表名称
     * @param playlistObject 播放列表对象，默认为当前播放列表
     * @returns 保存成功则返回 true，否则返回 false
     */
    async function save(name: string, playlistObject?: PlaylistObject): Promise<boolean> {
        // 默认为当前播放列表
        if (playlistObject === undefined) {
            playlistObject = playlist.playlist;
        }

        // 如果播放列表是随机播放
        // 则先恢复 items 的顺序
        if (playlistObject.shuffle) {
            playlistObject = {
                ...Playlist.object(),
                items: playlistObject.indexes.map((index) => playlistObject!.items[index]),
            };
        }

        // 仅保存 items
        const data = Playlist.extract(playlistObject, "items");

        try {
            await FopApi.writeJson(`star/${name}`, data.items);
            all.push(name);
            set.add(name);
        } catch (error) {
            console.error("保存收藏列表", name, "失败", error);
            return false;
        }

        return true;
    }

    /**
     * 删除某个收藏列表
     * @param name 收藏列表名称
     * @returns 删除成功则返回 true，否则返回 false
     */
    async function remove(name: string): Promise<boolean> {
        try {
            await FopApi.removeJson(`star/${name}`);
            all.splice(all.indexOf(name), 1);
            set.delete(name);
        } catch (error) {
            console.error("删除收藏列表", name, "失败", error);
            return false;
        }

        return true;
    }

    /**
     * 重命名收藏列表
     * @param oldName 原始收藏列表名称
     * @param newName 新的收藏列表名称
     * @returns 重命名成功则返回 true，否则返回 false
     */
    async function rename(oldName: string, newName: string): Promise<boolean> {
        try {
            await FopApi.renameJson(`star/${oldName}`, `star/${newName}`);
            all.splice(all.indexOf(oldName), 1, newName);
            set.delete(oldName);
            set.add(newName);
        } catch (error) {
            console.error("重命名收藏列表", oldName, "失败", error);
            return false;
        }

        return true;
    }

    return {
        all: computed(() => all),
        set: computed(() => set),
        build,
        load,
        save,
        remove,
        rename,
    };
});

if (import.meta.hot) {
    import.meta.hot.accept(acceptHMRUpdate(useStarStore, import.meta.hot));
}

export default useStarStore;
